home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / comm / mail / YAM23src.lha / Source / YAM_AB.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  50KB  |  1,161 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
  5.  Copyright (C) 2000-2001 by YAM Open Source Team
  6.  
  7.  This program is free software; you can redistribute it and/or modify
  8.  it under the terms of the GNU General Public License as published by
  9.  the Free Software Foundation; either version 2 of the License, or
  10.  (at your option) any later version.
  11.  
  12.  This program is distributed in the hope that it will be useful,
  13.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  GNU General Public License for more details.
  16.  
  17.  You should have received a copy of the GNU General Public License
  18.  along with this program; if not, write to the Free Software
  19.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  
  21.  YAM Official Support Site :  http://www.yam.ch
  22.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  23.  
  24.  $Id: YAM_AB.c,v 1.13.2.2 2001/06/08 14:29:37 laursen Exp $
  25.  
  26. ***************************************************************************/
  27.  
  28. #include "YAM.h"
  29.  
  30. /* local protos */
  31. LOCAL STACKEXT BOOL AB_FindTodaysBirthdates(struct MUI_NListtree_TreeNode*, long);
  32. LOCAL STACKEXT void AB_SaveTreeNode(FILE*, struct MUI_NListtree_TreeNode *);
  33. LOCAL void AB_PrintField(FILE*, char*, char*);
  34. LOCAL void AB_PrintShortEntry(FILE*, struct ABEntry*);
  35. LOCAL void AB_PrintLongEntry(FILE*, struct ABEntry*);
  36. LOCAL STACKEXT void AB_PrintLevel(struct MUI_NListtree_TreeNode*, FILE*, int);
  37.  
  38.  
  39. /***************************************************************************
  40.  Module: Address book
  41. ***************************************************************************/
  42.  
  43. /// AB_GotoEntry
  44. //  Searches an entry by alias and activates it
  45. APTR AB_GotoEntry(char *alias)
  46. {
  47.    int hits = 0;
  48.    struct MUI_NListtree_TreeNode *tn = NULL;
  49.    if (AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, alias, ASM_ALIAS|ASM_USER|ASM_GROUP|ASM_LIST, &hits, &tn))
  50.    {
  51.       DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Open, MUIV_NListtree_Open_ListNode_Parent, tn, 0);
  52.       set(G->AB->GUI.LV_ADRESSES, MUIA_NListtree_Active, tn);
  53.    }
  54.    return tn;
  55. }
  56.  
  57. ///
  58. /// AB_ExpandBD
  59. //  Converts date from numeric into textual format
  60. char *AB_ExpandBD(long date)
  61. {
  62.    static char datestr[SIZE_SMALL];
  63.    if (!date) return "";
  64.    sprintf(datestr, "%02d-%s-%ld", date/1000000, months[((date/10000)%100)-1], date%10000);
  65.    return datestr;
  66. }
  67.  
  68. ///
  69. /// AB_CompressBD
  70. //  Connverts date from textual into numeric format
  71. long AB_CompressBD(char *datestr)
  72. {
  73.    long d, m, y;
  74.    for (m = 12; m > 0; m--) if (!strnicmp(&datestr[3], months[m-1], 3)) break;
  75.    if (!m) return 0;
  76.    if ((d = atoi(datestr)) < 1 || d > 31) return 0;
  77.    if ((y = atoi(&datestr[7])) < 1800 || y > 2100) return 0;
  78.    return (100*d+m)*10000+y;
  79. }
  80.  
  81. ///
  82. /// AB_FindTodaysBirthdates (rec)
  83. //  Recursively searches the address book for a given birth date
  84. LOCAL STACKEXT BOOL AB_FindTodaysBirthdates(struct MUI_NListtree_TreeNode *list, long today)
  85. {
  86.    struct MUI_NListtree_TreeNode *tn;
  87.    int wrwin, i;
  88.    
  89.    for (i=0; ; i++)
  90.       if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, list, i, MUIV_NListtree_GetEntry_Flag_SameLevel))
  91.       {
  92.          struct ABEntry *ab = tn->tn_User;
  93.          if (ab->Type == AET_GROUP)
  94.          {
  95.             if (!AB_FindTodaysBirthdates(tn, today)) return FALSE;
  96.          }
  97.          else if (ab->Type == AET_USER && ab->BirthDay/10000 == today/10000)
  98.          {
  99.             char question[SIZE_LARGE], *name = *ab->RealName ? ab->RealName : ab->Alias;
  100.             sprintf(question, GetStr(MSG_AB_BirthdayReq), name, today%10000-ab->BirthDay%10000);
  101.             if (MUI_Request(G->App, G->MA->GUI.WI, 0, GetStr(MSG_AB_BirthdayReminder), GetStr(MSG_YesNoReq), question))
  102.             {
  103.                if ((wrwin = MA_NewNew(NULL, 0)) >= 0)
  104.                {
  105.                   setstring(G->WR[wrwin]->GUI.ST_TO, ab->Alias);
  106.                   setstring(G->WR[wrwin]->GUI.ST_SUBJECT, GetStr(MSG_AB_HappyBirthday));
  107.                }
  108.             }
  109.          }
  110.       }
  111.       else break;
  112.    return TRUE;
  113. }
  114.  
  115. ///
  116. /// AB_CheckBirthdates
  117. //  Searches address book for todays birth days
  118. void AB_CheckBirthdates(void)
  119. {
  120.    long today = DateStamp2Long(NULL);
  121.    AB_FindTodaysBirthdates(MUIV_NListtree_GetEntry_ListNode_Root, today);
  122. }
  123.  
  124. ///
  125. /// AB_SearchEntry (rec)
  126. //  Recursively searches the address book by alias, name or address
  127. STACKEXT int AB_SearchEntry(struct MUI_NListtree_TreeNode *list, char *text, int mode, int *hits, struct MUI_NListtree_TreeNode **lasthit)
  128. {
  129.    struct MUI_NListtree_TreeNode *tn;
  130.    int i;
  131.  
  132.    if (*text) for (i=0; ; i++)
  133.       if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, list, i, MUIV_NListtree_GetEntry_Flag_SameLevel))
  134.       {
  135.          struct ABEntry *ab = tn->tn_User;
  136.          int type = ab->Type;
  137.          BOOL found = FALSE;
  138.          if ((type == AET_USER && (mode&ASM_USER)) || (type == AET_LIST && (mode&ASM_LIST)) || (type == AET_GROUP && (mode&ASM_GROUP)))
  139.             if (mode&ASM_COMPLETE)
  140.             {
  141.                int tl = strlen(text);
  142.                switch (mode&ASM_TYPEMASK)
  143.                {
  144.                   case ASM_ALIAS   : found = !Strnicmp(ab->Alias, text, tl); break;
  145.                   case ASM_REALNAME: found = !Strnicmp(ab->RealName, text, tl); break;
  146.                   case ASM_ADDRESS : found = !Strnicmp(ab->Address, text, tl); break;
  147.                }
  148.             }
  149.             else
  150.                switch (mode&ASM_TYPEMASK)
  151.                {
  152.                   case ASM_ALIAS   : found = !Stricmp(ab->Alias, text); break;
  153.                   case ASM_REALNAME: found = !Stricmp(ab->RealName, text); break;
  154.                   case ASM_ADDRESS : found = !Stricmp(ab->Address, text); break;
  155.                }
  156.          if (found) { *lasthit = tn; *hits = *hits+1; };
  157.          if (type == AET_GROUP) AB_SearchEntry(tn, text, mode, hits, lasthit);
  158.       }
  159.       else break;
  160.    return *hits;
  161. }
  162.  
  163. ///
  164. /// AB_CompleteAlias
  165. //  Auto-completes alias or name in recipient field
  166. char *AB_CompleteAlias(char *text)
  167. {
  168.    char *compl = NULL;
  169.    struct MUI_NListtree_TreeNode *tn;
  170.    int hits = 0;
  171.    AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, text, ASM_ALIAS|ASM_USER|ASM_LIST|ASM_GROUP|ASM_COMPLETE, &hits, &tn);
  172.    if (hits == 1) compl = ((struct ABEntry *)(tn->tn_User))->Alias;
  173.    else if (!hits)
  174.    {
  175.       AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, text, ASM_REALNAME|ASM_USER|ASM_LIST|ASM_GROUP|ASM_COMPLETE, &hits, &tn);
  176.       if (hits == 1) compl = ((struct ABEntry *)(tn->tn_User))->RealName;
  177.       else if (!hits)
  178.       {
  179.           AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, text, ASM_ADDRESS|ASM_USER|ASM_LIST|ASM_GROUP|ASM_COMPLETE, &hits, &tn);
  180.           if (hits == 1) compl = ((struct ABEntry *)(tn->tn_User))->Address;
  181.       }
  182.    }
  183.    if (compl) return &compl[strlen(text)]; else return NULL;
  184. }
  185.  
  186. ///
  187. /// AB_InsertAddress
  188. //  Adds a new recipient to a recipient field
  189. void AB_InsertAddress(APTR string, char *alias, char *name, char *address)
  190. {
  191.    char *p;
  192.    get(string, MUIA_UserData, &p);
  193.    if ((BOOL)(p != NULL))
  194.    {
  195.       get(string, MUIA_String_Contents, &p);
  196.       if (*p) DoMethod(string, MUIM_BetterString_Insert, ", ", MUIV_BetterString_Insert_EndOfString);
  197.    }
  198.    else setstring(string, "");
  199.    if (*alias) DoMethod(string, MUIM_BetterString_Insert, alias, MUIV_BetterString_Insert_EndOfString);
  200.    else
  201.    {
  202.       if (*name)
  203.       {
  204.          if (strchr(name, ',')) DoMethod(string, MUIM_BetterString_Insert, "\"", MUIV_BetterString_Insert_EndOfString);
  205.          DoMethod(string, MUIM_BetterString_Insert, name, MUIV_BetterString_Insert_EndOfString);
  206.          if (strchr(name, ',')) DoMethod(string, MUIM_BetterString_Insert, "\"", MUIV_BetterString_Insert_EndOfString);
  207.       }
  208.       if (*address)
  209.       {
  210.          if (*name) DoMethod(string, MUIM_BetterString_Insert, " <", MUIV_BetterString_Insert_EndOfString);
  211.          DoMethod(string, MUIM_BetterString_Insert, address, MUIV_BetterString_Insert_EndOfString);
  212.          if (*name) DoMethod(string, MUIM_BetterString_Insert, ">", MUIV_BetterString_Insert_EndOfString);
  213.       }
  214.    }
  215. }
  216.  
  217. ///
  218. /// AB_FromAddrBook
  219. //  Inserts an address book entry into a recipient string
  220. void SAVEDS ASM AB_FromAddrBook(REG(a1,ULONG *arg))
  221. {
  222.    APTR string;
  223.    struct MUI_NListtree_TreeNode *active;
  224.  
  225.    if (active = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, NULL, MUIV_NListtree_GetEntry_Position_Active, 0))
  226.    {
  227.       int winnum = G->AB->WrWin;
  228.       struct ABEntry *addr = (struct ABEntry *)(active->tn_User);
  229.       BOOL openwin = winnum < 0;
  230.       if (!openwin) openwin = !G->WR[winnum];
  231.       if (openwin) G->AB->WrWin = winnum = MA_NewNew(NULL, 0);
  232.       if (winnum >= 0)
  233.       {
  234.          switch (*arg)
  235.          {
  236.             case ABM_TO:      string = G->WR[winnum]->GUI.ST_TO; break;
  237.             case ABM_CC:      string = G->WR[winnum]->GUI.ST_CC; break;
  238.             case ABM_BCC:     string = G->WR[winnum]->GUI.ST_BCC; break;
  239.             case ABM_REPLYTO: string = G->WR[winnum]->GUI.ST_REPLYTO; break;
  240.             case ABM_FROM:    string = G->WR[winnum]->GUI.ST_FROM; break;
  241.             default: string = (APTR)*arg;
  242.          }
  243.          AB_InsertAddress(string, addr->Alias, addr->RealName, "");
  244.       }
  245.    }
  246. }
  247. MakeHook(AB_FromAddrBookHook, AB_FromAddrBook);
  248.  
  249. ///
  250. /// AB_LoadTree
  251. //  Loads the address book from a file
  252. BOOL AB_LoadTree(char *fname, BOOL append, BOOL sorted)
  253. {
  254.    static struct ABEntry addr;
  255.    struct MUI_NListtree_TreeNode *parent[8];
  256.    char buffer[SIZE_LARGE];
  257.    FILE *fh;
  258.    int len, nested = 0;
  259.  
  260.    G->AB->Modified = append;
  261.    if (!append) DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Remove, MUIV_NListtree_Remove_ListNode_Root, MUIV_NListtree_Remove_TreeNode_All, 0);
  262.  
  263.    parent[nested] = MUIV_NListtree_Insert_ListNode_Root;
  264.    if (fh = fopen(fname, "r"))
  265.    {
  266.       GetLine(fh, buffer, SIZE_LARGE);
  267.       if (!strncmp(buffer,"YAB",3))
  268.       {
  269.          int version = buffer[3]-'0';
  270.          set(G->AB->GUI.LV_ADRESSES, MUIA_NListtree_Quiet, TRUE);
  271.          while (GetLine(fh, buffer, SIZE_LARGE))
  272.          {
  273.             clear(&addr, sizeof(struct ABEntry));
  274.             if (!strncmp(buffer, "@USER", 5))
  275.             {
  276.                addr.Type = AET_USER;
  277.                stccpy(addr.Alias   , Trim(&buffer[6]),SIZE_NAME);
  278.                stccpy(addr.Address , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_ADDRESS);
  279.                stccpy(addr.RealName, Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_REALNAME);
  280.                stccpy(addr.Comment , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  281.                if (version > 2)
  282.                {
  283.                   stccpy(addr.Phone   , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);;
  284.                   stccpy(addr.Street  , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  285.                   stccpy(addr.City    , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  286.                   stccpy(addr.Country , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  287.                   stccpy(addr.PGPId   , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  288.                   addr.BirthDay = atol(Trim(GetLine(fh, buffer, SIZE_LARGE)));
  289.                   stccpy(addr.Photo   , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_PATHFILE);
  290.                   if (strcmp(GetLine(fh, buffer, SIZE_LARGE), "@ENDUSER"))    stccpy(addr.Homepage,Trim(buffer),SIZE_URL);
  291.                }
  292.                     if(version > 3)
  293.                     {
  294.                         addr.DefSecurity = atoi(Trim(GetLine(fh, buffer, SIZE_LARGE)));
  295.                     }
  296.                do if (!strcmp(buffer, "@ENDUSER")) break;
  297.                while (GetLine(fh, buffer, SIZE_LARGE));
  298.                DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Insert, addr.Alias[0] ? addr.Alias : addr.RealName, &addr, parent[nested], sorted ?  MUIV_NListtree_Insert_PrevNode_Sorted : MUIV_NListtree_Insert_PrevNode_Tail, 0);
  299.             }
  300.             else if (!strncmp(buffer, "@LIST", 5))
  301.             {
  302.                char *members;
  303.                addr.Type = AET_LIST;
  304.  
  305.                stccpy(addr.Alias   , Trim(&buffer[6]), SIZE_NAME);
  306.                if (version > 2)
  307.                {
  308.                   stccpy(addr.Address , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_ADDRESS);
  309.                   stccpy(addr.RealName, Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_REALNAME);
  310.                }
  311.                stccpy(addr.Comment , Trim(GetLine(fh, buffer, SIZE_LARGE)), SIZE_DEFAULT);
  312.                members = AllocStrBuf(SIZE_DEFAULT);
  313.                while (GetLine(fh, buffer, SIZE_LARGE))
  314.                {
  315.                   if (!strcmp(buffer, "@ENDLIST")) break;
  316.                   if (!*buffer) continue;
  317.                   members = StrBufCat(members, buffer);
  318.                   members = StrBufCat(members, "\n");
  319.                }
  320.                len = strlen(members)+1;
  321.                addr.Members = malloc(len);
  322.                strcpy(addr.Members, members);
  323.                FreeStrBuf(members);
  324.                DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Insert, addr.Alias, &addr, parent[nested], sorted ?  MUIV_NListtree_Insert_PrevNode_Sorted : MUIV_NListtree_Insert_PrevNode_Tail, 0);
  325.                free(addr.Members);
  326.             }
  327.             else if (!strncmp(buffer, "@GROUP", 6))
  328.             {
  329.                addr.Type = AET_GROUP;
  330.                stccpy(addr.Alias  , Trim(&buffer[7]), SIZE_NAME);
  331.                stccpy(addr.Comment, Trim(GetLine(fh, buffer, SIZE_LARGE)), SIZE_DEFAULT);
  332.                nested++;
  333.                parent[nested] = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Insert, addr.Alias, &addr, parent[nested-1], MUIV_NListtree_Insert_PrevNode_Tail, TNF_LIST);
  334.             }
  335.             else if (!strcmp(buffer,"@ENDGROUP"))
  336.             {
  337.                nested--;
  338.             }
  339.          }
  340.          set(G->AB->GUI.LV_ADRESSES, MUIA_NListtree_Quiet, FALSE);
  341.       }
  342.       else
  343.       {
  344.          fseek(fh, 0, SEEK_SET);
  345.          while (GetLine(fh, buffer, SIZE_LARGE))
  346.          {
  347.             char *p, *p2;
  348.             clear(&addr, sizeof(struct ABEntry));
  349.             if (p = strchr(buffer, ' ')) *p = 0;
  350.             stccpy(addr.Address, buffer, SIZE_ADDRESS);
  351.             if (p)
  352.             {
  353.                stccpy(addr.RealName, ++p, SIZE_REALNAME);
  354.                if (p2 = strchr(p, ' ')) *p2 = 0;
  355.             }
  356.             else if (p2 = strchr(p = buffer, '@')) *p2 = 0;
  357.             stccpy(addr.Alias, p, SIZE_NAME);
  358.             DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Insert, addr.Alias, &addr, parent[nested], sorted ?  MUIV_NListtree_Insert_PrevNode_Sorted : MUIV_NListtree_Insert_PrevNode_Tail, 0);
  359.          }
  360.       }
  361.       fclose(fh);
  362.    }
  363.    else return FALSE;
  364.  
  365.    return TRUE;
  366. }
  367.  
  368. ///
  369. /// AB_SaveTreeNode (rec)
  370. //  Recursively saves an address book node
  371. LOCAL STACKEXT void AB_SaveTreeNode(FILE *fh, struct MUI_NListtree_TreeNode *list)
  372. {
  373.    struct MUI_NListtree_TreeNode *tn;
  374.    struct ABEntry *ab;
  375.    int i;
  376.         
  377.    for (i=0; ; i++)
  378.       if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, list, i, MUIV_NListtree_GetEntry_Flag_SameLevel))
  379.       {
  380.          ab = tn->tn_User;
  381.          switch (ab->Type)
  382.          {
  383.             case AET_USER:  fprintf(fh, "@USER %s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%08ld\n%s\n%s\n%d\n@ENDUSER\n", ab->Alias, ab->Address, ab->RealName, ab->Comment,
  384.                                ab->Phone, ab->Street, ab->City, ab->Country, ab->PGPId, ab->BirthDay, ab->Photo, ab->Homepage, ab->DefSecurity);
  385.                             break;
  386.             case AET_LIST:  fprintf(fh, "@LIST %s\n%s\n%s\n%s\n%s\n@ENDLIST\n", ab->Alias, ab->Address, ab->RealName, ab->Comment, ab->Members);
  387.                             break;
  388.             case AET_GROUP: fprintf(fh, "@GROUP %s\n%s\n", ab->Alias, ab->Comment);
  389.                             AB_SaveTreeNode(fh, tn);
  390.                             fputs("@ENDGROUP\n", fh);
  391.                             break;
  392.          }
  393.       }
  394.       else break;
  395. }
  396.  
  397. ///
  398. /// AB_SaveTree
  399. //  Saves the address book to a file
  400. BOOL AB_SaveTree(char *fname)
  401. {
  402.    FILE *fh;
  403.  
  404.    if (fh = fopen(fname, "w"))
  405.    {
  406.       fputs("YAB4 - YAM Addressbook\n", fh);
  407.       AB_SaveTreeNode(fh, MUIV_NListtree_GetEntry_ListNode_Root);
  408.       fclose(fh);
  409.       AppendLogVerbose(70, GetStr(MSG_LOG_SavingABook), fname, "", "", "");
  410.       return TRUE;
  411.    }
  412.    ER_NewError(GetStr(MSG_ER_CantCreateFile), fname, NULL);
  413.    return FALSE;
  414. }
  415.  
  416. ///
  417. /// AB_DoubleClick
  418. //  User double-clicked in the address book
  419. void SAVEDS AB_DoubleClick(void)
  420. {
  421.    extern void AB_EditFunc(void);
  422.  
  423.    if (G->AB->WrWin >= 0) if (G->WR[G->AB->WrWin])
  424.    {
  425.       struct WR_GUIData *gui = &G->WR[G->AB->WrWin]->GUI;
  426.       APTR obj = NULL;
  427.       switch (G->AB->Mode)
  428.       {
  429.          case ABM_TO:      obj = gui->ST_TO; break;
  430.          case ABM_CC:      obj = gui->ST_CC; break;
  431.          case ABM_BCC:     obj = gui->ST_BCC; break;
  432.          case ABM_FROM:    obj = gui->ST_FROM; break;
  433.          case ABM_REPLYTO: obj = gui->ST_REPLYTO; break;
  434.       }
  435.       DoMethod(G->App, MUIM_CallHook, &AB_FromAddrBookHook, obj);
  436.       set(G->AB->GUI.WI, MUIA_Window_CloseRequest, TRUE);
  437.       return;
  438.    }
  439.    AB_EditFunc();
  440. }
  441. MakeHook(AB_DoubleClickHook, AB_DoubleClick);
  442. ///
  443.  
  444. /// AB_Sort
  445. //  Sorts the address book
  446. void SAVEDS ASM AB_Sort(REG(a1,int *arg))
  447. {
  448.    char fname[SIZE_PATHFILE];
  449.    strmfp(fname, C->TempDir, ".addressbook.tmp");
  450.    if (AB_SaveTree(fname))
  451.    {
  452.       G->AB->SortBy = *arg;
  453.       AB_LoadTree(fname, FALSE, TRUE);
  454.       remove(fname);
  455.       G->AB->Modified = TRUE;
  456.    }
  457. }
  458. MakeHook(AB_SortHook, AB_Sort);
  459.  
  460. ///
  461. /// AB_NewABookFunc
  462. //  Clears entire address book
  463. void SAVEDS AB_NewABookFunc(void)
  464. {
  465.    DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Remove, MUIV_NListtree_Remove_ListNode_Root, MUIV_NListtree_Remove_TreeNode_All, 0);
  466.    G->AB->Modified = FALSE;
  467. }
  468. MakeHook(AB_NewABookHook, AB_NewABookFunc);
  469.  
  470. ///
  471. /// AB_OpenABookFunc
  472. //  Loads selected address book
  473. void SAVEDS AB_OpenABookFunc(void)
  474. {
  475.    if (ReqFile(ASL_ABOOK,G->AB->GUI.WI, GetStr(MSG_Open), 0, G->MA_MailDir, ""))
  476.    {
  477.       strmfp(G->AB_Filename, G->ASLReq[ASL_ABOOK]->fr_Drawer, G->ASLReq[ASL_ABOOK]->fr_File);
  478.       AB_LoadTree(G->AB_Filename, FALSE, FALSE);
  479.    }
  480. }
  481. MakeHook(AB_OpenABookHook, AB_OpenABookFunc);
  482.  
  483. ///
  484. /// AB_AppendABookFunc
  485. //  Appends selected address book
  486. void SAVEDS AB_AppendABookFunc(void)
  487. {
  488.    if (ReqFile(ASL_ABOOK,G->AB->GUI.WI, GetStr(MSG_Append), 0, G->MA_MailDir, ""))
  489.    {
  490.       char aname[SIZE_PATHFILE];
  491.       strmfp(aname, G->ASLReq[ASL_ABOOK]->fr_Drawer, G->ASLReq[ASL_ABOOK]->fr_File);
  492.       AB_LoadTree(aname, TRUE, FALSE);
  493.    }
  494. }
  495. MakeHook(AB_AppendABookHook, AB_AppendABookFunc);
  496.  
  497. ///
  498. /// AB_SaveABookFunc
  499. //  Saves address book using the default name
  500. void SAVEDS AB_SaveABookFunc(void)
  501. {
  502.    Busy(GetStr(MSG_BusySavingAB), G->AB_Filename, 0, 0);
  503.    AB_SaveTree(G->AB_Filename);
  504.    G->AB->Modified = FALSE;
  505.    BusyEnd;
  506. }
  507. MakeHook(AB_SaveABookHook, AB_SaveABookFunc);
  508.  
  509. ///
  510. /// AB_SaveABookAsFunc
  511. //  Saves address book under a different name
  512. void SAVEDS AB_SaveABookAsFunc(void)
  513. {
  514.    if (ReqFile(ASL_ABOOK,G->AB->GUI.WI, GetStr(MSG_SaveAs), 1, G->MA_MailDir, ""))
  515.    {
  516.       strmfp(G->AB_Filename, G->ASLReq[ASL_ABOOK]->fr_Drawer, G->ASLReq[ASL_ABOOK]->fr_File);
  517.       AB_SaveABookFunc();
  518.    }
  519. }
  520. MakeHook(AB_SaveABookAsHook, AB_SaveABookAsFunc);
  521.  
  522. ///
  523. /// AB_PrintField
  524. //  Formats and prints a single field
  525. LOCAL void AB_PrintField(FILE *prt, char *fieldname, char *field)
  526. {
  527. const char *format = "%-20.20s: %-50.50s\n";
  528.    if (*field) fprintf(prt, format, StripUnderscore(fieldname), field);
  529. }
  530.  
  531. ///
  532. /// AB_PrintShortEntry
  533. //  Prints an address book entry in compact format
  534. LOCAL void AB_PrintShortEntry(FILE *prt, struct ABEntry *ab)
  535. {
  536.    char types[3] = { 'P','L','G' };
  537.    fprintf(prt, "%c %-12.12s %-20.20s %-36.36s\n", types[ab->Type-AET_USER],
  538.       ab->Alias, ab->RealName, ab->Type == AET_USER ? ab->Address : ab->Comment);
  539. }
  540.  
  541. ///
  542. /// AB_PrintLongEntry
  543. //  Prints an address book entry in detailed format
  544. LOCAL void AB_PrintLongEntry(FILE *prt, struct ABEntry *ab)
  545. {
  546.    fputs("------------------------------------------------------------------------\n", prt);
  547.    switch (ab->Type)
  548.    {
  549.       case AET_USER:
  550.          AB_PrintField(prt, GetStr(MSG_AB_PersonAlias), ab->Alias);
  551.          AB_PrintField(prt, GetStr(MSG_EA_RealName), ab->RealName);
  552.          AB_PrintField(prt, GetStr(MSG_EA_EmailAddress), ab->Address);
  553.          AB_PrintField(prt, GetStr(MSG_EA_PGPId), ab->PGPId);
  554.          AB_PrintField(prt, GetStr(MSG_EA_Homepage), ab->Homepage);
  555.          AB_PrintField(prt, GetStr(MSG_EA_Street), ab->Street);
  556.          AB_PrintField(prt, GetStr(MSG_EA_City), ab->City);
  557.          AB_PrintField(prt, GetStr(MSG_EA_Country), ab->Country);
  558.          AB_PrintField(prt, GetStr(MSG_EA_Phone), ab->Phone);
  559.          AB_PrintField(prt, GetStr(MSG_EA_DOB), AB_ExpandBD(ab->BirthDay));
  560.          break;
  561.       case AET_LIST:
  562.          AB_PrintField(prt, GetStr(MSG_AB_ListAlias), ab->Alias);
  563.          AB_PrintField(prt, GetStr(MSG_EA_MLName), ab->RealName);
  564.          AB_PrintField(prt, GetStr(MSG_EA_ReturnAddress), ab->Address);
  565.          if (ab->Members)
  566.          {
  567.             BOOL header = FALSE;
  568.             char *ptr;
  569.             for (ptr = ab->Members; *ptr; ptr++)
  570.             {
  571.                char *nptr = strchr(ptr, '\n');
  572.                if (nptr) *nptr = 0; else break;
  573.                if (!header) { AB_PrintField(prt, GetStr(MSG_EA_Members), ptr); header = TRUE; }
  574.                else fprintf(prt, "                      %s\n", ptr);
  575.                *nptr = '\n';
  576.                ptr = nptr;
  577.             }
  578.          }
  579.          break;
  580.       case AET_GROUP:
  581.          AB_PrintField(prt, GetStr(MSG_AB_GroupAlias), ab->Alias);
  582.    }
  583.    AB_PrintField(prt, GetStr(MSG_EA_Description), ab->Comment);
  584. }
  585.  
  586. ///
  587. /// AB_PrintLevel (rec)
  588. //  Recursively prints an address book node
  589. LOCAL STACKEXT void AB_PrintLevel(struct MUI_NListtree_TreeNode *list, FILE *prt, int mode)
  590. {
  591.    struct MUI_NListtree_TreeNode *tn;
  592.    int i;
  593.    
  594.    for (i=0; ; i++)
  595.       if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, list, i, MUIV_NListtree_GetEntry_Flag_SameLevel))
  596.       {
  597.          struct ABEntry *ab = tn->tn_User;
  598.          if (mode == 1) AB_PrintLongEntry(prt, ab); else AB_PrintShortEntry(prt, ab);
  599.          if (ab->Type == AET_GROUP) AB_PrintLevel(tn, prt, mode);
  600.       }
  601.       else break;
  602. }
  603.  
  604. ///
  605. /// AB_PrintABookFunc
  606. //  Prints the entire address book in compact or detailed format
  607. void SAVEDS AB_PrintABookFunc(void)
  608. {
  609.    FILE *prt;
  610.    int mode = MUI_Request(G->App, G->AB->GUI.WI, 0, GetStr(MSG_Print), GetStr(MSG_AB_PrintReqGads), GetStr(MSG_AB_PrintReq));
  611.    if (!mode) return;
  612.    if (C->PrinterCheck) if (!CheckPrinter()) return;
  613.    if (prt = fopen("PRT:", "w"))
  614.    {
  615.       Busy(GetStr(MSG_BusyPrintingAB), "", 0, 0);
  616.       fprintf(prt, "%s\n", G->AB_Filename);
  617.       if (mode == 2)
  618.       {
  619.          fprintf(prt, "\n  %-12.12s %-20.20s %s/%s\n", GetStr(MSG_AB_AliasFld), GetStr(MSG_EA_RealName), GetStr(MSG_EA_EmailAddress), GetStr(MSG_EA_Description));
  620.          fputs("------------------------------------------------------------------------\n", prt);
  621.       }
  622.       AB_PrintLevel(MUIV_NListtree_GetEntry_ListNode_Root, prt, mode);
  623.       fclose(prt);
  624.       BusyEnd;
  625.    }
  626. }
  627. MakeHook(AB_PrintABookHook, AB_PrintABookFunc);
  628.  
  629. ///
  630. /// AB_PrintFunc
  631. //  Prints selected address book entry in detailed format
  632. void SAVEDS AB_PrintFunc(void)
  633. {
  634.    FILE *prt;
  635.    struct MUI_NListtree_TreeNode *tn;
  636.    if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, MUIV_NListtree_GetEntry_ListNode_Active, MUIV_NListtree_GetEntry_Position_Active, 0))
  637.    {
  638.       if (C->PrinterCheck) if (!CheckPrinter()) return;
  639.       if (prt = fopen("PRT:", "w"))
  640.       {
  641.          struct ABEntry *ab = (struct ABEntry *)(tn->tn_User);
  642.          set(G->App, MUIA_Application_Sleep, TRUE);
  643.          AB_PrintLongEntry(prt, ab);
  644.          if (ab->Type == AET_GROUP) AB_PrintLevel(tn, prt, 1);
  645.          fclose(prt);
  646.          set(G->App, MUIA_Application_Sleep, FALSE);
  647.       }
  648.    }
  649. }
  650. MakeHook(AB_PrintHook, AB_PrintFunc);
  651.  
  652. ///
  653. /// AB_AddEntryFunc
  654. //  Add a new entry to the address book
  655. void SAVEDS ASM AB_AddEntryFunc(REG(a1,int *arg))
  656. {
  657.    EA_Init(*arg, NULL);
  658. }
  659. MakeHook(AB_AddEntryHook, AB_AddEntryFunc);
  660.  
  661. ///
  662. /// AB_EditFunc
  663. //  Modifies selected address book entry
  664. void SAVEDS AB_EditFunc(void)
  665. {
  666.    struct MUI_NListtree_TreeNode *tn;
  667.    if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, MUIV_NListtree_GetEntry_ListNode_Active, MUIV_NListtree_GetEntry_Position_Active, 0))
  668.    {
  669.       struct ABEntry *ab = (struct ABEntry *)(tn->tn_User);
  670.       int winnum = EA_Init(ab->Type, tn);
  671.       if (winnum >= 0) EA_Setup(winnum, ab);
  672.    }
  673. }
  674. MakeHook(AB_EditHook, AB_EditFunc);
  675.  
  676. ///
  677. /// AB_DeleteFunc
  678. //  Deletes selected address book entry
  679. void SAVEDS AB_DeleteFunc(void)
  680. {
  681.    DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_Remove, NULL, MUIV_NListtree_Remove_TreeNode_Active, 0);
  682.    G->AB->Modified = TRUE;
  683. }
  684. MakeHook(AB_DeleteHook, AB_DeleteFunc);
  685.  
  686. ///
  687. /// AB_DuplicateFunc
  688. //  Duplicates selected address book entry
  689. void SAVEDS AB_DuplicateFunc(void)
  690. {
  691.    struct MUI_NListtree_TreeNode *tn;
  692.    if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, MUIV_NListtree_GetEntry_ListNode_Active, MUIV_NListtree_GetEntry_Position_Active, 0))
  693.    {
  694.       struct ABEntry *ab = (struct ABEntry *)(tn->tn_User);
  695.       int winnum = EA_Init(ab->Type, NULL);
  696.       if (winnum >= 0) 
  697.       {
  698.          char buf[SIZE_NAME];
  699.          int len;
  700.          EA_Setup(winnum, ab);
  701.          strcpy(buf, ab->Alias);
  702.          if (len = strlen(buf))
  703.          {
  704.             if (isdigit(buf[len-1])) buf[len-1]++;
  705.             else if (len < SIZE_NAME-1) strcat(buf, "2");
  706.             else buf[len-1] = '2';
  707.             setstring(G->EA[winnum]->GUI.ST_ALIAS, buf);
  708.          }
  709.       }
  710.    }
  711. }
  712. MakeHook(AB_DuplicateHook, AB_DuplicateFunc);
  713.  
  714. ///
  715. /// AB_FindEntry (rec)
  716. //  Recursively searches an address book node for a given pattern
  717. STACKEXT BOOL AB_FindEntry(struct MUI_NListtree_TreeNode *list, char *pattern, int mode, char **result)
  718. {
  719.    APTR lv = G->AB->GUI.LV_ADRESSES;
  720.    struct MUI_NListtree_TreeNode *tn;
  721.    int i;
  722.    
  723.    for (i=0; ; i++)
  724.       if (tn = (struct MUI_NListtree_TreeNode *)DoMethod(lv, MUIM_NListtree_GetEntry, list, i, MUIV_NListtree_GetEntry_Flag_SameLevel))
  725.       {
  726.          struct ABEntry *ab = tn->tn_User;
  727.          if (ab->Type == AET_GROUP)
  728.          {
  729.             if (!AB_FindEntry(tn, pattern, mode, result)) return FALSE;
  730.          }
  731.          else
  732.          {
  733.             int found = 0, winnum;
  734.             switch (mode)
  735.             {
  736.                case ABF_RX_NAME:       if (ab->Type != AET_GROUP) found |= astcsma(ab->RealName, pattern); break;
  737.                case ABF_RX_EMAIL:      if (ab->Type != AET_GROUP) found |= astcsma(ab->Address, pattern); break;
  738.                case ABF_RX_NAMEEMAIL:  if (ab->Type != AET_GROUP) found |= astcsma(ab->RealName, pattern) | astcsma(ab->Address, pattern); break;
  739.                default:
  740.                   found |= astcsma(ab->Alias, pattern) | astcsma(ab->Comment, pattern);
  741.                   if (ab->Type != AET_GROUP) found |= astcsma(ab->RealName, pattern) | astcsma(ab->Address, pattern);
  742.                   if (ab->Type == AET_USER) found |= astcsma(ab->Homepage, pattern) | astcsma(ab->Street, pattern) | astcsma(ab->City, pattern) | astcsma(ab->Country, pattern) | astcsma(ab->Phone, pattern);
  743.             }
  744.             if (found)
  745.             {
  746.                G->AB->Hits++;
  747.                if (mode == ABF_USER)
  748.                {
  749.                   char buf[SIZE_LARGE];
  750.                   DoMethod(lv, MUIM_NListtree_Open, MUIV_NListtree_Open_ListNode_Parent, tn, 0);
  751.                   set(lv, MUIA_NListtree_Active, tn);
  752.                   sprintf(buf, GetStr(MSG_AB_FoundEntry), ab->Alias, ab->RealName);
  753.                   switch (MUI_Request(G->App, G->AB->GUI.WI, 0, GetStr(MSG_AB_FindEntry), GetStr(MSG_AB_FoundEntryGads), buf))
  754.                   {
  755.                      case 1: break;
  756.                      case 2: if ((winnum = EA_Init(ab->Type, tn)) >= 0) EA_Setup(winnum, ab);
  757.                      case 0: return FALSE;
  758.                   }
  759.                }
  760.                else if (result) *result++ = ab->Alias;
  761.             }
  762.          }
  763.       }
  764.       else break;
  765.    return TRUE;
  766. }
  767.  
  768. ///
  769. /// AB_FindFunc
  770. //  Searches address book
  771. void SAVEDS AB_FindFunc(void)
  772. {
  773.    static char pattern[SIZE_PATTERN] = { 0 };
  774.  
  775.    G->AB->Hits = 0;
  776.    if (StringRequest(pattern, SIZE_PATTERN, GetStr(MSG_AB_FindEntry), GetStr(MSG_AB_FindEntryReq), GetStr(MSG_AB_StartSearch), NULL, GetStr(MSG_Cancel), FALSE, G->AB->GUI.WI))
  777.    {
  778.       AB_FindEntry(MUIV_NListtree_GetEntry_ListNode_Root, pattern, ABF_USER, NULL);
  779.       if (!G->AB->Hits) MUI_Request(G->App, G->AB->GUI.WI, 0, GetStr(MSG_AB_FindEntry), GetStr(MSG_OkayReq), GetStr(MSG_AB_NoneFound));
  780.    }
  781. }
  782. MakeHook(AB_FindHook, AB_FindFunc);
  783. ///
  784.  
  785. /// AB_OpenFunc
  786. //  Open address book window
  787. void SAVEDS ASM AB_OpenFunc(REG(a1,int *arg))
  788. {
  789.    struct AB_ClassData *ab = G->AB;
  790.    char *md = "";
  791.  
  792.    switch (ab->Mode = arg[0])
  793.    {
  794.       case ABM_TO:      md = "(To)"; break;
  795.       case ABM_CC:      md = "(CC)"; break;
  796.       case ABM_BCC:     md = "(BCC)"; break;
  797.       case ABM_FROM:    md = "(From)"; break;
  798.       case ABM_REPLYTO: md = "(Reply-To)"; break;
  799.    }
  800.    ab->WrWin = *md ? arg[1] : -1;
  801.    ab->Modified = FALSE;
  802.    sprintf(ab->WTitle, "%s %s", GetStr(MSG_MA_MAddrBook), md);
  803.    set(ab->GUI.WI, MUIA_Window_Title, ab->WTitle);
  804.    set(ab->GUI.LV_ADRESSES, MUIA_NListtree_Active, MUIV_NListtree_Active_Off);
  805.    SafeOpenWindow(ab->GUI.WI);
  806. }
  807. MakeHook(AB_OpenHook, AB_OpenFunc);
  808.  
  809. ///
  810. /// AB_Close
  811. //  Closes address book window
  812. void SAVEDS AB_Close(void)
  813. {
  814.    if (G->AB->Modified) switch (MUI_Request(G->App, G->AB->GUI.WI, 0, NULL, GetStr(MSG_AB_ModifiedGads), GetStr(MSG_AB_Modified)))
  815.    {
  816.       case 0: return;
  817.       case 1: AB_SaveABookFunc(); break;
  818.       case 2: break;
  819.       case 3: AB_LoadTree(G->AB_Filename, FALSE, FALSE);
  820.    }
  821.    set(G->AB->GUI.WI, MUIA_Window_Open, FALSE);
  822. }
  823. MakeHook(AB_CloseHook, AB_Close);
  824. ///
  825.  
  826. /// AB_LV_ConFunc
  827. //  Address book listview construction hook
  828. struct ABEntry * SAVEDS ASM AB_LV_ConFunc(REG(a1, struct MUIP_NListtree_ConstructMessage *msg))
  829. {
  830.    struct ABEntry *entry = malloc(sizeof(struct ABEntry));
  831.  
  832.    if (entry != NULL && msg != NULL)
  833.    {
  834.         struct ABEntry *addr = (struct ABEntry *)msg->UserData;
  835.  
  836.       memcpy(entry, addr, sizeof(struct ABEntry));
  837.       if (addr->Members) strcpy(entry->Members = malloc(strlen(addr->Members)+1), addr->Members);
  838.    }
  839.  
  840.    return entry;
  841. }
  842. MakeHook(AB_LV_ConFuncHook, AB_LV_ConFunc);
  843.  
  844. ///
  845. /// AB_LV_DesFunc
  846. //  Address book listview destruction hook
  847. long SAVEDS ASM AB_LV_DesFunc(REG(a1, struct MUIP_NListtree_DestructMessage *msg))
  848. {
  849.    struct ABEntry *entry;
  850.  
  851.    if(msg)
  852.    {
  853.            entry = (struct ABEntry *)msg->UserData;
  854.  
  855.       if(entry)
  856.       {
  857.                if (entry->Members) free(entry->Members);
  858.                free(entry);
  859.       }
  860.    }
  861.  
  862.    return 0;
  863. }
  864. MakeHook(AB_LV_DesFuncHook, AB_LV_DesFunc);
  865.  
  866. ///
  867. /// AB_LV_DspFunc
  868. //  Address book listview display hook
  869. long SAVEDS ASM AB_LV_DspFunc(REG(a0, struct Hook *hook), REG(a1, struct MUIP_NListtree_DisplayMessage *msg))
  870. {
  871.    static char dispal[SIZE_DEFAULT];
  872. // static char dispco[SIZE_DEFAULT+8];
  873. // struct AL_Data *data = (APTR)hook->h_Data;
  874.  
  875.    if (msg != NULL && msg->TreeNode != NULL)
  876.    {
  877.       struct ABEntry *entry = msg->TreeNode->tn_User;
  878.  
  879.       if (entry)
  880.       {
  881.          msg->Array[0] = entry->Alias;
  882.          msg->Array[1] = entry->RealName;
  883.          msg->Array[3] = entry->Address;
  884.          msg->Array[4] = entry->Street;
  885.          msg->Array[5] = entry->City;
  886.          msg->Array[6] = entry->Country;
  887.          msg->Array[7] = entry->Phone;
  888.          msg->Array[8] = AB_ExpandBD(entry->BirthDay);
  889.          msg->Array[9] = entry->PGPId;
  890.          msg->Array[10]= entry->Homepage;
  891.  
  892.          switch (entry->Type)
  893.          {
  894. /*
  895.             case AET_USER:  msg->Array[0] = entry->Alias;
  896.                             msg->Array[2] = entry->Comment;
  897.                             break;
  898.             case AET_LIST:  if (data->Image) sprintf(msg->Array[0] = dispal, "\033O[%08lx]%s", data->Image, entry->Alias);
  899.                             else strcpy(msg->Array[0] = dispal, entry->Alias);
  900.                             msg->Array[2] = entry->Comment;
  901.                             break;
  902.             case AET_GROUP: sprintf(msg->Array[0] = dispal, MUIX_B"%s", entry->Alias);
  903.                             sprintf(msg->Array[2] = dispco, MUIX_B"%s", entry->Comment);
  904. */
  905.             case AET_LIST:
  906.             {
  907.                sprintf(msg->Array[0] = dispal, "\033o[0] %s", entry->Alias);
  908.             }
  909.             break;
  910.  
  911.             case AET_GROUP:
  912.             {
  913.                msg->Preparse[0] = MUIX_B;
  914.                msg->Preparse[2] = MUIX_B;
  915.             }
  916.             break;
  917.          }
  918.       }
  919.    }
  920.    else
  921.    {
  922.       msg->Array[0] = GetStr(MSG_AB_TitleAlias);
  923.       msg->Array[1] = GetStr(MSG_AB_TitleName);
  924.       msg->Array[2] = GetStr(MSG_AB_TitleDescription);
  925.       msg->Array[3] = GetStr(MSG_AB_TitleAddress);
  926.       msg->Array[4] = GetStr(MSG_AB_TitleStreet);
  927.       msg->Array[5] = GetStr(MSG_AB_TitleCity);
  928.       msg->Array[6] = GetStr(MSG_AB_TitleCountry);
  929.       msg->Array[7] = GetStr(MSG_AB_TitlePhone);
  930.       msg->Array[8] = GetStr(MSG_AB_TitleBirthDate);
  931.       msg->Array[9] = GetStr(MSG_AB_TitlePGPId);
  932.       msg->Array[10]= GetStr(MSG_AB_TitleHomepage);
  933.    }
  934.    return 0;
  935. }
  936. MakeHook(AB_LV_DspFuncHook, AB_LV_DspFunc);
  937.  
  938. ///
  939. /// AB_LV_CmpFunc
  940. //  Address book listview sort hook
  941. /*
  942. long SAVEDS ASM AB_LV_CmpFunc(REG(a2,struct MUI_NListtree_TreeNode *entry1), REG(a1,struct MUI_NListtree_TreeNode *entry2))
  943. {
  944.    char *n1, *n2;
  945.    struct ABEntry *ab1 = (struct ABEntry *)entry1->tn_User,
  946.                   *ab2 = (struct ABEntry *)entry2->tn_User;
  947.    int cmp;
  948.    switch (G->AB->SortBy)
  949.    {
  950.       case 1: if (!(n1 = strrchr(ab1->RealName,' '))) n1 = ab1->RealName;
  951.               if (!(n2 = strrchr(ab2->RealName,' '))) n2 = ab2->RealName;
  952.               if (cmp = Stricmp(n1, n2)) return cmp;
  953.               break;
  954.       case 2: if (cmp = Stricmp(ab1->RealName, ab2->RealName)) return cmp;
  955.               break;
  956.       case 3: if (cmp = Stricmp(ab1->Comment, ab2->Comment)) return cmp;
  957.               break;
  958.       case 4: if (cmp = Stricmp(ab1->Address, ab2->Address)) return cmp;
  959.               break;
  960.    }
  961.    return Stricmp(ab1->Alias, ab2->Alias);
  962. }
  963. MakeHook(AB_LV_CmpFuncHook, AB_LV_CmpFunc);
  964. */
  965. ///
  966.  
  967. /// AB_MakeABFormat
  968. //  Creates format definition for address book listview
  969. void AB_MakeABFormat(APTR lv)
  970. {
  971.    int i;
  972.    char format[SIZE_LARGE];
  973.    BOOL first = TRUE;
  974.    *format = 0;
  975.    for (i = 0; i < ABCOLNUM; i++) if (C->AddrbookCols & (1<<i))
  976.    {
  977.       if (first) first = FALSE; else strcat(format, " BAR,");
  978.       sprintf(&format[strlen(format)], "COL=%ld W=-1", i);
  979.    }
  980.    set(lv, MUIA_NListtree_Format, format);
  981. }
  982.  
  983. ///
  984. /// AB_New
  985. //  Creates address book window
  986. enum { AMEN_NEW,AMEN_OPEN,AMEN_APPEND,AMEN_SAVE,AMEN_SAVEAS,AMEN_PRINTA,
  987.        AMEN_FIND,AMEN_NEWUSER,AMEN_NEWLIST,AMEN_NEWGROUP,AMEN_EDIT,
  988.        AMEN_DUPLICATE,AMEN_DELETE,AMEN_PRINTE,AMEN_SORTALIAS,
  989.        AMEN_SORTLNAME,AMEN_SORTFNAME,AMEN_SORTDESC,AMEN_SORTADDR,
  990.        AMEN_FOLD,AMEN_UNFOLD };
  991.  
  992. struct AB_ClassData *AB_New(void)
  993. {
  994.    struct AB_ClassData *data;
  995.    APTR list;
  996.  
  997.    if (data = calloc(1, sizeof(struct AB_ClassData)))
  998.    {
  999.       APTR tb_butt[13] = { MSG_AB_TBSave,MSG_AB_TBFind,MSG_Space,
  1000.                            MSG_AB_TBNewUser,MSG_AB_TBNewList,MSG_AB_TBNewGroup,MSG_AB_TBEdit,MSG_AB_TBDelete,MSG_AB_TBPrint,MSG_Space,
  1001.                            MSG_AB_TBOpenTree,MSG_AB_TBCloseTree,NULL };
  1002.       APTR tb_help[13] = { MSG_HELP_AB_BT_SAVE,MSG_HELP_AB_BT_SEARCH,NULL,
  1003.                            MSG_HELP_AB_BT_ADDUSER,MSG_HELP_AB_BT_ADDMLIST,MSG_HELP_AB_BT_ADDGROUP,MSG_HELP_AB_BT_EDIT,MSG_HELP_AB_BT_DELETE,MSG_HELP_AB_BT_PRINT,NULL,
  1004.                            MSG_HELP_AB_BT_OPEN,MSG_HELP_AB_BT_CLOSE,NULL };
  1005.       int i;
  1006.       for (i = 0; i < 13; i++) SetupToolbar(&(data->GUI.TB_TOOLBAR[i]), tb_butt[i]?(tb_butt[i]==MSG_Space?"":GetStr(tb_butt[i])):NULL, tb_help[i]?GetStr(tb_help[i]):NULL, 0);
  1007.       data->GUI.WI = WindowObject,
  1008.          MUIA_HelpNode,"AB_W",
  1009.          MUIA_Window_Menustrip, MenustripObject,
  1010.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_CO_CrdABook),
  1011.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_New), MUIA_Menuitem_Shortcut,"N", MUIA_UserData,AMEN_NEW, End,
  1012.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Open), MUIA_Menuitem_Shortcut,"O", MUIA_UserData,AMEN_OPEN, End,
  1013.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Append), MUIA_Menuitem_Shortcut,"I", MUIA_UserData,AMEN_APPEND, End,
  1014.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  1015.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Save), MUIA_Menuitem_Shortcut,"S", MUIA_UserData,AMEN_SAVE, End,
  1016.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_SaveAs), MUIA_Menuitem_Shortcut,"A", MUIA_UserData,AMEN_SAVEAS, End,
  1017.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  1018.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_MIFind), MUIA_Menuitem_Shortcut,"F", MUIA_UserData,AMEN_FIND, End,
  1019.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Print), MUIA_UserData,AMEN_PRINTA, End,
  1020.             End,
  1021.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_AB_Entry),
  1022.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_AddUser), MUIA_Menuitem_Shortcut,"P", MUIA_UserData,AMEN_NEWUSER, End,
  1023.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_AddList), MUIA_Menuitem_Shortcut,"L", MUIA_UserData,AMEN_NEWLIST, End,
  1024.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_AddGroup), MUIA_Menuitem_Shortcut,"G", MUIA_UserData,AMEN_NEWGROUP, End,
  1025.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  1026.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Edit), MUIA_Menuitem_Shortcut,"E", MUIA_UserData,AMEN_EDIT, End,
  1027.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_Duplicate), MUIA_Menuitem_Shortcut,"D", MUIA_UserData,AMEN_DUPLICATE, End,
  1028.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_MIDelete), MUIA_Menuitem_Shortcut,"Del", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,AMEN_DELETE, End,
  1029.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  1030.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_MIPrint), MUIA_UserData,AMEN_PRINTE, End,
  1031.             End,
  1032.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_AB_Sort),
  1033.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByAlias), MUIA_Menuitem_Shortcut,"1", MUIA_UserData,AMEN_SORTALIAS, End,
  1034.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByName), MUIA_Menuitem_Shortcut,"2", MUIA_UserData,AMEN_SORTLNAME, End,
  1035.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByFirstname), MUIA_Menuitem_Shortcut,"3", MUIA_UserData,AMEN_SORTFNAME, End,
  1036.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByDesc), MUIA_Menuitem_Shortcut,"4", MUIA_UserData,AMEN_SORTDESC, End,
  1037.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByAddress), MUIA_Menuitem_Shortcut,"5", MUIA_UserData,AMEN_SORTADDR, End,
  1038.             End,
  1039.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_AB_View),
  1040.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_Unfold), MUIA_Menuitem_Shortcut,"<", MUIA_UserData,AMEN_UNFOLD, End,
  1041.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_Fold), MUIA_Menuitem_Shortcut,">", MUIA_UserData,AMEN_FOLD, End,
  1042.             End,
  1043.          End,
  1044.          MUIA_Window_ID,MAKE_ID('B','O','O','K'),
  1045.          WindowContents, VGroup,
  1046.             Child, C->HideGUIElements & HIDE_TBAR ?
  1047.                (HGroup,
  1048.                   MUIA_HelpNode, "AB_B",
  1049.                   Child, data->GUI.BT_TO  = MakeButton("_To:"),
  1050.                   Child, data->GUI.BT_CC  = MakeButton("_CC:"),
  1051.                   Child, data->GUI.BT_BCC = MakeButton("_BCC:"),
  1052.                End) :
  1053.                (HGroup, GroupSpacing(0),
  1054.                   MUIA_HelpNode, "AB_B",
  1055.                   Child, VGroup,
  1056.                      MUIA_Weight, 10,
  1057.                      MUIA_Group_VertSpacing, 0,
  1058.                      Child, data->GUI.BT_TO  = MakeButton("_To:"),
  1059.                      Child, data->GUI.BT_CC  = MakeButton("_CC:"),
  1060.                      Child, data->GUI.BT_BCC = MakeButton("_BCC:"),
  1061.                      Child, HVSpace,
  1062.                   End,
  1063.                   Child, MUI_MakeObject(MUIO_VBar, 12),
  1064.                   Child, HGroupV,
  1065.                      Child, data->GUI.TO_TOOLBAR = ToolbarObject,
  1066.                         MUIA_Toolbar_ImageType,      MUIV_Toolbar_ImageType_File,
  1067.                         MUIA_Toolbar_ImageNormal,    "PROGDIR:Icons/Address.toolbar",
  1068.                         MUIA_Toolbar_ImageGhost,     "PROGDIR:Icons/Address_G.toolbar",
  1069.                         MUIA_Toolbar_ImageSelect,    "PROGDIR:Icons/Address_S.toolbar",
  1070.                         MUIA_Toolbar_Description,    data->GUI.TB_TOOLBAR,
  1071.                         MUIA_Toolbar_ParseUnderscore,TRUE,
  1072.                         MUIA_Font,                   MUIV_Font_Tiny,
  1073.                         MUIA_ShortHelp, TRUE,
  1074.                      End,
  1075.                      Child, HSpace(0),
  1076.                   End,
  1077.                End),
  1078.  
  1079.             Child, list = NListviewObject,
  1080.                MUIA_CycleChain,                 TRUE,
  1081.                MUIA_Listview_DragType,     MUIV_Listview_DragType_Immediate,
  1082.                MUIA_NListview_NList,        data->GUI.LV_ADRESSES = NewObject(CL_AddressList->mcc_Class, NULL,
  1083.                   InputListFrame,
  1084.                   //MUIA_NListtree_SortHook,                &AB_LV_CmpFuncHook,
  1085.                   MUIA_NListtree_DragDropSort,        TRUE,
  1086.                   MUIA_NListtree_Title,                        TRUE,
  1087.                   MUIA_NListtree_ConstructHook,        &AB_LV_ConFuncHook,
  1088.                   MUIA_NListtree_DestructHook,        &AB_LV_DesFuncHook,
  1089.                   MUIA_NListtree_DisplayHook,        &AB_LV_DspFuncHook,
  1090.                   MUIA_NListtree_EmptyNodes,            TRUE,
  1091.                   MUIA_Font,                                             C->FixedFontList ? MUIV_Font_Fixed : MUIV_Font_List,
  1092.                End,
  1093.             End,
  1094.          End,
  1095.       End;
  1096.  
  1097.       // If we successfully created the WindowObject
  1098.       if (data->GUI.WI)
  1099.       {
  1100.           AB_MakeABFormat(data->GUI.LV_ADRESSES);
  1101.           DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  1102.           set(data->GUI.WI, MUIA_Window_DefaultObject, list);
  1103.           SetHelp(data->GUI.BT_TO ,MSG_HELP_AB_BT_TO );
  1104.           SetHelp(data->GUI.BT_CC ,MSG_HELP_AB_BT_CC );
  1105.           SetHelp(data->GUI.BT_BCC,MSG_HELP_AB_BT_BCC);
  1106.  
  1107.         // Now we add the group image to the NListtree
  1108.         DoMethod(data->GUI.LV_ADRESSES, MUIM_NList_UseImage, G->MA->GUI.BC_STAT[11], 0, 0, TAG_DONE);
  1109.  
  1110.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEW      ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_NewABookHook,0);
  1111.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_OPEN     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_OpenABookHook,0);
  1112.         DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_APPEND   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AppendABookHook,0);
  1113.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SAVE     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SaveABookHook,0);
  1114.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SAVEAS   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SaveABookAsHook,0);
  1115.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_PRINTA   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_PrintABookHook,0);
  1116.         DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEWUSER  ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AddEntryHook,AET_USER);
  1117.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEWLIST  ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AddEntryHook,AET_LIST);
  1118.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEWGROUP ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AddEntryHook,AET_GROUP);
  1119.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_EDIT     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_EditHook,0);
  1120.         DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_DUPLICATE,MUIV_Notify_Application,3,MUIM_CallHook,&AB_DuplicateHook,0);
  1121.            DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_DELETE   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_DeleteHook,0);
  1122.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_PRINTE   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_PrintHook,0);
  1123.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_FIND     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_FindHook,0);
  1124.         DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTALIAS,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,0);
  1125.         DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTLNAME,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,1);
  1126.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTFNAME,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,2);
  1127.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTDESC ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,3);
  1128.           DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTADDR ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,4);
  1129.         DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_FOLD     ,data->GUI.LV_ADRESSES,4,MUIM_NListtree_Close ,NULL,MUIV_NListtree_Close_TreeNode_All,0);
  1130.            DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_UNFOLD   ,data->GUI.LV_ADRESSES,4,MUIM_NListtree_Open  ,NULL,MUIV_NListtree_Open_TreeNode_All,0);
  1131.           DoMethod(data->GUI.LV_ADRESSES,MUIM_Notify,MUIA_NListtree_DoubleClick,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook,&AB_DoubleClickHook,0);
  1132.           DoMethod(data->GUI.BT_TO      ,MUIM_Notify,MUIA_Pressed    ,FALSE,MUIV_Notify_Application           ,3,MUIM_CallHook       ,&AB_FromAddrBookHook,ABM_TO);
  1133.         DoMethod(data->GUI.BT_CC      ,MUIM_Notify,MUIA_Pressed    ,FALSE,MUIV_Notify_Application           ,3,MUIM_CallHook       ,&AB_FromAddrBookHook,ABM_CC);
  1134.            DoMethod(data->GUI.BT_BCC     ,MUIM_Notify,MUIA_Pressed    ,FALSE,MUIV_Notify_Application           ,3,MUIM_CallHook       ,&AB_FromAddrBookHook,ABM_BCC);
  1135.  
  1136.           if (data->GUI.TO_TOOLBAR)
  1137.           {
  1138.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 0, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_SaveABookHook,0);
  1139.           DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 1, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_FindHook,0);
  1140.              DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 3, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_AddEntryHook,AET_USER);
  1141.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 4, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_AddEntryHook,AET_LIST);
  1142.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 5, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_AddEntryHook,AET_GROUP);
  1143.           DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 6, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_EditHook,0);
  1144.              DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 7, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_DeleteHook,0);
  1145.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 8, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_PrintHook,0);
  1146.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,10, MUIV_Toolbar_Notify_Pressed,FALSE,data->GUI.LV_ADRESSES,4,MUIM_NListtree_Open  ,NULL,MUIV_NListtree_Open_TreeNode_All,0);
  1147.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,11, MUIV_Toolbar_Notify_Pressed,FALSE,data->GUI.LV_ADRESSES,4,MUIM_NListtree_Close ,NULL,MUIV_NListtree_Close_TreeNode_All,0);
  1148.           }
  1149.  
  1150.           DoMethod(data->GUI.WI,MUIM_Notify,MUIA_Window_InputEvent   ,"-repeat del" ,MUIV_Notify_Application  ,2,MUIM_CallHook       ,&AB_DeleteHook);
  1151.           DoMethod(data->GUI.WI,MUIM_Notify,MUIA_Window_CloseRequest ,TRUE ,MUIV_Notify_Application           ,2,MUIM_CallHook       ,&AB_CloseHook);
  1152.  
  1153.             return data;
  1154.       }
  1155.       free(data);
  1156.    }
  1157.    return NULL;
  1158. }
  1159. ///
  1160.  
  1161.